package com.test.uimremote;

import android.Manifest;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.*;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import com.qualcomm.uimremoteclient.IUimRemoteClientService;
import com.qualcomm.uimremoteclient.IUimRemoteClientServiceCallback;
import com.test.uimremote.jni.XmClient;
import com.test.uimremote.sim.ServerProxy;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.test.uimremote.sim.ServerProxy.byte2hex;


public class MainActivity extends AppCompatActivity {

    // TODO: 2020/3/6
    /////test
    private static final byte[] atr = {0x3B, (byte) 0x9D, (byte) 0x95, (byte) 0x80, 0x1F, (byte) 0xC7, (byte) 0x80, 0x31, (byte) 0xE0, 0x73, (byte) 0xFE, 0x21, 0x13, 0x65, 0x15, 0x09, 0x63, (byte) 0x86, (byte) 0x83, (byte) 0xA1};

    private IUimRemoteClientService mService = null;
    private ServiceConnection mConnection = new UimRemoteServiceConnection();
    private Context context;

    private ServerProxy mServerProxy;

    public static class UimSlot {
        public static final int UIM_REMOTE_SLOT0 = 0;
        public static final int UIM_REMOTE_SLOT1 = 1;
        public static final int UIM_REMOTE_SLOT2 = 2;
    }

    ;

    public static class UimRemoteEvent {
        public static final int UIM_REMOTE_CONNECTION_UNAVAILABLE = 0;
        public static final int UIM_REMOTE_CONNECTION_AVAILABLE = 1;
        public static final int UIM_REMOTE_CARD_INSERT = 2;
        public static final int UIM_REMOTE_CARD_REMOVED = 3;
        public static final int UIM_REMOTE_CARD_ERROR = 4;
        public static final int UIM_REMOTE_CARD_RESET = 5;
        public static final int UIM_REMOTE_CARD_WAKEUP = 6;
    }

    ;

    public static class UimRemoteErrcode {
        public static final int UIM_REMOTE_CARD_ERROR_UNKNOWN = 0;
        public static final int IM_REMOTE_CARD_ERROR_NO_LINK_EST = 1;
        public static final int IM_REMOTE_CARD_ERROR_CMD_TIMEOUT = 2;
        public static final int UIM_REMOTE_CARD_ERROR_POWER_DOWN = 3;
        public static final int UIM_REMOTE_CARD_ERROR_POWER_DOWN_TELECOM = 4;
    }

    ;

    public static class UimRemoteRspCode {
        public static final int UIM_REMOTE_SUCCESS = 0;
        public static final int UIM_REMOTE_ERROR = 1;
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 获取权限
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 3);
        }

        context = this;
        mServerProxy = new ServerProxy(getApplicationContext());

        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.qualcomm.uimremoteclient", "com.qualcomm.uimremoteclient.UimRemoteClientService"));
        System.out.println("bind the uimremoteclientservice");
        boolean ret = bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        System.out.println("bind the uimremoteclientservice result " + ret);

        Button connectButton = (Button) findViewById(R.id.Connect);
        Button disconnectButton = (Button) findViewById(R.id.Disconnect);
        Button networkButton = findViewById(R.id.network);
        Button disconnectNetworkButton = findViewById(R.id.disconnect);

        connectButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                System.out.println("connect button clicked");

                try {
                    int ret = mService.uimRemoteEvent(UimSlot.UIM_REMOTE_SLOT0, UimRemoteEvent.UIM_REMOTE_CONNECTION_AVAILABLE, atr,
                            UimRemoteErrcode.UIM_REMOTE_CARD_ERROR_UNKNOWN, false, 0, false, 0,
                            true, 7, true, 1, false, 0);
                    System.out.println("connect uimRemoteEvent result " + ret);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        disconnectButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                System.out.println("connect button clicked");
                //TODO delete later
                try {
                    Signature[] sigs = context.getPackageManager().getPackageInfo(
                            context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
                    for (Signature sig : sigs) {
                        final byte[] rawCert = sig.toByteArray();
                        InputStream certStream = new ByteArrayInputStream(rawCert);
                        final CertificateFactory certFactory = CertificateFactory.getInstance("X509");
                        final X509Certificate x509cert = (X509Certificate) certFactory.generateCertificate(certStream);
                        byte[] certByte = x509cert.getEncoded();

                        MessageDigest md = MessageDigest.getInstance("SHA-1");
                        md.update(certByte);
                        byte[] certThumbprint = md.digest();
                        final StringBuilder sb = new StringBuilder();
                        for (byte bt : certThumbprint) {
                            sb.append(String.format("%02x", bt));
                        }
                        System.out.println("cert " + sb.toString());
                    }
                } catch (PackageManager.NameNotFoundException | CertificateException | NoSuchAlgorithmException e) {
                    e.printStackTrace();
                }

                try {
                    int ret = mService.uimRemoteEvent(UimSlot.UIM_REMOTE_SLOT0, UimRemoteEvent.UIM_REMOTE_CONNECTION_UNAVAILABLE, atr,
                            UimRemoteErrcode.UIM_REMOTE_CARD_ERROR_UNKNOWN, false, 0, false, 0,
                            false, 0, true, 1, false, 0);
                    System.out.println("disconnect uimRemoteEvent result " + ret);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        TextView domainNameView = findViewById(R.id.domainName);
        TextView ipView = findViewById(R.id.ip);
        TextView portView = findViewById(R.id.port);
        networkButton.setOnClickListener((v) -> {
            XmClient.init(domainNameView.getText().toString(), ipView.getText().toString(), Integer.parseInt(portView.getText().toString()));
            new Thread(() -> XmClient.start()).start();
        });
        disconnectNetworkButton.setOnClickListener((v) -> {
            XmClient.stop();
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mConnection);
    }


    private class UimRemoteServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            mService = IUimRemoteClientService.Stub.asInterface((IBinder) service);

            if (mService != null) {
                try {
                    int ret = mService.registerCallback(mcb);
                    System.out.println("registerCallback uimremoteclientservice result " + ret);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            mServerProxy.setAidlService(mService);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mService = null;
            mServerProxy.setAidlService(null);
        }
    }

    private final IUimRemoteClientServiceCallback mcb = new IUimRemoteClientServiceCallback.Stub() {
        @Override
        public void uimRemoteEventResponse(int slot, int responseCode) throws RemoteException {
            if (responseCode != UimRemoteRspCode.UIM_REMOTE_SUCCESS) {
                System.out.println("uimRemoteEventResponse responseCode" + responseCode);
            }
            System.out.println("uimRemoteEventResponse responseCode" + responseCode);
        }

        @Override
        public void uimRemoteApduResponse(int slot, int responseCode) throws RemoteException {
            if (responseCode != UimRemoteRspCode.UIM_REMOTE_SUCCESS) {
                System.out.println("uimRemoteApduResponse responseCode" + responseCode);
            }
            System.out.println("uimRemoteApduResponse responseCode" + responseCode);
        }

        @Override
        public void uimRemoteApduIndication(int slot, byte[] apduCmd) throws RemoteException {
            System.out.println("uimRemoteApduIndication received");
            final StringBuilder sb = new StringBuilder();
            for (byte bt : apduCmd) {
                sb.append(String.format("%02x ", bt));
            }
            System.out.println("Received APDU command " + sb.toString());


            // TODO: 2020/3/6
            Log.i("proxyTest", "收到高通数据,apduCmd.length=" + apduCmd.length + ",buffer=" + byte2hex(apduCmd));
            mServerProxy.writeToJni(apduCmd);

        }

        @Override
        public void uimRemoteConnectIndication(int slot) throws RemoteException {
            System.out.println("uimRemoteConnectIndication received");
            try {
                int ret = mService.uimRemoteEvent(UimSlot.UIM_REMOTE_SLOT0, UimRemoteEvent.UIM_REMOTE_CARD_RESET, atr,
                        UimRemoteErrcode.UIM_REMOTE_CARD_ERROR_UNKNOWN, false, 0, false, 0,
                        false, 0, true, 1, false, 0);
                System.out.println("disconnect uimRemoteEvent result" + ret);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void uimRemoteDisconnectIndication(int slot) throws RemoteException {
            System.out.println("uimRemoteConnectIndication received");

        }

        @Override
        public void uimRemotePowerUpIndication(int slot) throws RemoteException {
            System.out.println("uimRemotePowerUpIndication received");
            mService.uimRemoteApdu(slot, 0, atr);
        }

        @Override
        public void uimRemotePowerDownIndication(int slot) throws RemoteException {
            System.out.println("uimRemotePowerDownIndication received");
        }

        @Override
        public void uimRemoteResetIndication(int slot) throws RemoteException {
            System.out.println("uimRemotePowerUpIndication received");
            mService.uimRemoteApdu(slot, 0, atr);
        }

        @Override
        public void uimRemoteRadioStateIndication(int slot, int state) throws RemoteException {
            System.out.println("uimRemoteRadioStateIndication received");
        }
    };
}
